;;; init-evil.el --- Bring vim back -*- lexical-binding: t -*-

;;; Commentary:
;;

;;; Code:
;; evil from doom




;; 延迟加载evil，use-package :hook直接写包含相关的包名会直接立即加载，因此单独写一个函数，用lamda放到use-package 会立即加载
(defvar evil-loaded nil)
(defun load-evil! ()
  (when (not evil-loaded)
    ;; (message "require evil before") ;; 顺序2
    (require 'evil)
    ;; (message "require evil after") ;; 顺序3
    (setq evil-loaded t))
    )

(use-package evil
  :hook (emacs-startup . load-evil!)
  :bind (([remap evil-scroll-up] . pixel-scroll-interpolate-up)
          ([remap evil-scroll-down] . pixel-scroll-interpolate-down))
  :init
  ;; hook执行之前就会执行
  ;; (message "init evil") 顺序1
  (setq evil-want-keybinding nil) ;; before evil
  ;; (setq evil-want-C-i-jump nil)
  (setq evil-disable-insert-state-bindings t)
  (setq evil-want-Y-yank-to-eol t)
  ;; (setq evil-want-keybinding nil)
  ;; :bind (([remap evil-quit] . kill-this-buffer)
  ;;        :map evil-motion-state-map
  ;;        ("f" . evil-avy-goto-char-in-line)
  ;;        :map evil-normal-state-map
  ;;        ("s" . evil-avy-goto-char-timer))
  :custom
  (evil-want-keybinding nil)
  (evil-want-C-u-scroll t)
  ;; undo will never freeze my Emacs
  (evil-undo-system 'undo-redo)
  ;; Switch to the new window after splitting
  (evil-split-window-below t)
  (evil-vsplit-window-right t)
  (evil-ex-complete-emacs-commands nil)
  (evil-ex-interactive-search-highlight 'selected-window)
  ;; when `visual-line-mode' enabled, exchange j/k with gj/gk
  (evil-respect-visual-line-mode t)
  (evil-want-integration t)
  (evil-want-fine-undo t)
  (evil-want-C-g-bindings t)
  (evil-want-abbrev-expand-on-insert-exit nil)
  (evil-symbol-word-search t)
  :config
  ;; (require 'init-evil)
  (defalias 'evil-scroll-up 'pixel-scroll-interpolate-up)
  (defalias 'evil-scroll-down 'pixel-scroll-interpolate-down)

  (evil-mode t))

(use-package evil-collection
  :after evil ;; 必须在evil之后，用hook会被覆盖
  ;; :hook (evil-mode . evil-collection-init)
  :custom
  (evil-collection-setup-debugger-keys nil)
  (evil-collection-calendar-want-org-bindings t)
  (evil-collection-unimpaired-want-repeat-mode-integration t)
  :config
  (setq evil-overriding-maps nil)
  (evil-collection-init)
  )

  (defun +evil/shift-right ()
    "vnoremap < <gv"
    (interactive)
    (call-interactively #'evil-shift-right)
    (evil-normal-state)
    (evil-visual-restore))

  (defun +evil/shift-left ()
    "vnoremap > >gv"
    (interactive)
    (call-interactively #'evil-shift-left)
    (evil-normal-state)
    (evil-visual-restore))
  ;; 缩进之后保持选中
(with-eval-after-load 'evil
  (evil-define-key 'visual 'evil-visual-state-map "<" '+evil/shift-left)
  (evil-define-key 'visual 'evil-visual-state-map ">" '+evil/shift-right)

;; 太卡
;; (use-package undo-tree
;;   
;;   :init
;;   (global-undo-tree-mode 1)
;;   (setq undo-tree-auto-save-history t)
;;   (evil-set-undo-system 'undo-tree))

;; 定义leaderkey相关
(define-key evil-normal-state-map " " nil)
(evil-set-leader 'normal (kbd "SPC"))
(evil-set-leader 'normal (kbd "<leader><leader>") :localleader)
  
(defun define-leader-key (state map localleader &rest bindings)
      "Define leader key in MAP when STATE, a wrapper for
`evil-define-key*'. All BINDINGS are prefixed with \"<leader>\"
if LOCALLEADER is nil, otherwise \"<localleader>\"."
      (cl-assert (cl-evenp (length bindings)))
      (let ((prefix (if localleader "<SPC><SPC>" "<SPC>")) ;; 不知道<leader>和<localleader>which-key-add-key-based-replacements无法识别
            wk-replacements)
        (while bindings
          (let ((key (pop bindings))
                (def (pop bindings)))
            (when (symbolp def)
              (evil-define-key* state map (kbd (concat prefix key)) def))
            ;; Save which-key (key . replacement).
            (pcase def
              (`(:wk ,replacement)
               (push (cons (concat prefix key) replacement) wk-replacements)))))
        ;; which-key integration.
        ;; XXX: replacement for localleader NOT supported.
        ;; lexical-binding t, 否则wk-replacement为空
        (with-eval-after-load 'which-key
          (cl-loop for (key . replacement) in wk-replacements
                   ;; unless localleader
                   do (which-key-add-key-based-replacements key replacement)))))

(defun open-auto-terminal ()
              (interactive)
              (if (display-graphic-p)
                  (eaf-open-pyqterminal)
                  (ansi-term (getenv "SHELL"))))


(defun zilongshanren/evil-quick-replace (beg end )
  (interactive "r")
  (when (evil-visual-state-p)
    (evil-exit-visual-state)
    (let ((selection (regexp-quote (buffer-substring-no-properties beg end))))
      (setq command-string (format "%%s /%s//g" selection))
      (minibuffer-with-setup-hook
	  (lambda () (backward-char 2))
	(evil-ex command-string)))))

(define-key evil-visual-state-map (kbd "C-r") 'zilongshanren/evil-quick-replace))

(use-package evil-snipe
  :after evil
  :init
  (evil-snipe-mode -1)
  (evil-snipe-override-mode +1))

;; (use-package evil-matchit
;;   
;;   :init
;;   (global-evil-matchit-mode 1))

(provide 'init-evil)
